package com.product.android.business.manager;

import com.product.android.utils.LogUtils;

import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;

public abstract class MotionEventManager {
	private static final int CLICK_CRITICAL_VALUE=35;
	private static final int LONG_CLICK_TIME=700;		//按住500毫秒就是系统就会认为是longClick
	private View mView;
	private float mStartX;		//起始x坐标
	private float mStartY;
	private float mNowX;		//当前x坐标
	private float mNowY;
	private float mOriDistance;	//多点触控时的原始距离
	private float mOriArea;		//原始面积
	private float mNowArea;
	private float mScale;		//放大的�1ￄ1�7�数
	private float mTripleScale;
	private float mSourceComputeValue;		//用于计算放大之后的�1ￄ1�7�的原始数据
	private float mCriticalXValue;			//判断左划或�1ￄ1�7�右划的临界倄1�7�1�7
	private float mCriticalYValue;			//判断上划或�1ￄ1�7�下划的临界倄1�7�1�7
	private boolean mbIsDoubleTouch=false;	//两点
	private boolean mbIsTripleTouch=false;	//三点
	private boolean mbCanBeClick=false;		//是否可认为是点击事件
	private boolean mbLongClickNotified=false;	//长点击事件是否已提醒
	private boolean mbIsSingleDown=false;
	protected boolean mbChangeBackGroundNotified=false;
	private int mChangeBackGroundTime=100;
	private int mLongClickTime=LONG_CLICK_TIME;
	private int mPressId=0;
	public MotionEventManager(View view){
		mView=view;
		mView.setOnTouchListener(onTouchListener);
	}
	
	public void setSourceComputeValue(float value){
		mSourceComputeValue=value;
	}
	
	public void setLongClickTime(int time){
		if (time>LONG_CLICK_TIME){
			mLongClickTime=time;
		}
	}
	
	private OnTouchListener onTouchListener=new OnTouchListener() {
		boolean result=false;
		@Override
		public boolean onTouch(View v, MotionEvent event) {
			MotionEventManager.this.onTouch();
			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				mStartX=event.getX();
				mStartY=event.getY();
				result=onDown(mStartX, mStartY);
				mbCanBeClick=true;
				mbIsSingleDown=true;
				mbChangeBackGroundNotified=false;
				mPressId++;
				final MyHandler handler=new MyHandler();
				handler.setId(mPressId);
				handler.postDelayed(new Runnable() {
					public void run() {
						if (handler.isIdChanged(mPressId)){
							return;
						}
						if (mbCanBeClick && mbIsSingleDown){
							debug("mbCanBeClick && mbIsSingleDown && mbLongClickNotified="+mbLongClickNotified);
							if (!mbLongClickNotified){
								debug("mbLongClickNotified="+mbLongClickNotified);	
								onLongClick(mStartX, mStartY);
								mbLongClickNotified=true;
							}
						}
					}
				}, LONG_CLICK_TIME);
//				new Handler().postDelayed(new Runnable() {
//					public void run() {
//						if (mbCanBeClick && mbIsSingleDown){
//							debug("mbCanBeClick && mbIsSingleDown && mbLongClickNotified="+mbLongClickNotified);
//							if (!mbLongClickNotified){
//								debug("mbLongClickNotified="+mbLongClickNotified);	
//								onLongClick(mStartX, mStartY);
//								mbLongClickNotified=true;
//							}
//						}
//					}
//				}, LONG_CLICK_TIME*2);
//				debug("ACTION_DOWN");
				break;
			case MotionEvent.ACTION_UP:
				mNowX=event.getX();
				mNowY=event.getY();
				mbIsSingleDown=false;
				mbLongClickNotified=false;
				if (mbIsDoubleTouch){
					//多点触控的话直接结束此次监听
					mbIsDoubleTouch=false;
					break;
				}
				result=onUp(mNowX, mNowY);
				if (result){
					if (mbChangeBackGroundNotified){
						onReStore(mNowX, mNowY);
					}
					break;
				}
				if (mbCanBeClick){
					//是单击事仄1�7�1�7
					float timePassed=event.getEventTime()-event.getDownTime();
					if (timePassed<mLongClickTime){
						//还未达长点击时间
						result=onClick();
						if (mbChangeBackGroundNotified){
							onReStore(mNowX, mNowY);
						}else{
							onPress(mNowX, mNowY);
							new Handler().postDelayed(new Runnable() {
								public void run() {
									onReStore(mNowX, mNowY);		
								}
							}, mChangeBackGroundTime);
						}
						if (result){
							break;
						}
					}
				}
				float deltaX=mNowX-mStartX;
				float deltaY=mNowY-mStartY;
				float absX=Math.abs(deltaX);
				float absY=Math.abs(deltaY);
//					Log.d(tag, "absX="+absX+",absY="+absY+",deltaX="+deltaX+",deltaY="+deltaY+",criticalValue="+mCriticalXValue);
				if (absX>absY){
					//横向位移比纵向位移大，认为是横向划动
					if (absX>mCriticalXValue){
						//位移超过临界倄1�7�1�7
						if (deltaX>0){
							//右划
							result=onSlipRight(deltaX);
						}else{
							//左划
							result=onSlipLeft(deltaX);
						}
					}
				}else{
					//纵向划动
					if (absY>mCriticalYValue){
						if (deltaY>0){
							//下划
							result=onSlipDown(deltaY);
						}else{
							//上划
							result=onSlipUp(deltaY);
						}
					}
				}
				if (mbChangeBackGroundNotified){
					onReStore(mNowX, mNowY);
				}
//				debug("ACTION_UP");
				break;
			case MotionEvent.ACTION_MOVE:
				mNowX=event.getX();
				mNowY=event.getY();
				float offset=getDistance(mNowX, mNowY, mStartX, mStartY);
				if (offset>CLICK_CRITICAL_VALUE){
					//移动距离过大，不认为是单击事件
//					debug("finger moved,not to be considered as click");
					mbCanBeClick=false;
				}
				
				onMove(mStartX, mNowX, mStartY, mNowY);
				if(mbIsTripleTouch){
					int count=event.getPointerCount();
					if (count>2){
						mNowArea=getArea(event);
						mTripleScale=mNowArea/mOriArea;
						result=onTripleZoom(mTripleScale);
					}else{
						mbIsTripleTouch=false;
					}
				}else if (mbIsDoubleTouch){
					int count=event.getPointerCount();
					if (count>1){
						float nowDistance=getDistance(event.getX(0),event.getY(0),event.getX(1),event.getY(1));
						mScale=nowDistance/mOriDistance;
						result=onZoom(mScale,mSourceComputeValue);
					}else{
						mbIsDoubleTouch=false;
					}
				}else{
					if (mbCanBeClick){
						if (mbLongClickNotified){
							break;
						}
						float timePassed=event.getEventTime()-event.getDownTime();
						if (timePassed>mLongClickTime){
							result=onLongClick(mNowX,mNowY);
							mbLongClickNotified=true;
							if (result){
								break;
							}	
						}else if (timePassed>mChangeBackGroundTime){
							if (!mbChangeBackGroundNotified){
								onPress(mNowX, mNowY);
								mbChangeBackGroundNotified=true;	
							}
						}
					}
				}
//				debug("ACTION_MOVE");
				break;
			case MotionEvent.ACTION_POINTER_2_DOWN:
				int count=event.getPointerCount();
				mbIsSingleDown=false;
				if (count>=2){
					mOriDistance=getDistance(event.getX(0),event.getY(0),event.getX(1),event.getY(1));
					result=onDoubleTouchTown();
					mbIsDoubleTouch=true;
					mbCanBeClick=false;
				}else{
					mbIsDoubleTouch=false;
				}
				break;
			case MotionEvent.ACTION_POINTER_3_DOWN:
				count=event.getPointerCount();
				mbIsSingleDown=false;
				if (count>=3){
					result=onTripleTouchTown();
					mbIsDoubleTouch=false;
					mbCanBeClick=false;
					mbIsTripleTouch=true;
					mOriArea=getArea(event);
				}else{
					mbIsTripleTouch=false;
					mbIsDoubleTouch=false;
				}
				break;
			case MotionEvent.ACTION_POINTER_1_UP:
			case MotionEvent.ACTION_POINTER_2_UP:
				mbIsDoubleTouch=false;
				break;
			case MotionEvent.ACTION_POINTER_3_UP:
				mbIsTripleTouch=false;
				break;

			default:
				break;
			}
			return result;
		}
	};
	
	public void setCriticalValues(float x,float y){
		mCriticalXValue=x;
		mCriticalYValue=y;
	}
	
	/**
	 * @n<b>函数名称</b>     :getDistance
	 * @brief	根据两点的坐标获取二者的距离
	 * @see
	 * @since    Ver 1.1
	 * @param  @param sX
	 * @param  @param sY
	 * @param  @param eX
	 * @param  @param eY
	 * @param  @return
	 * @return float
	 * @<b>作�1ￄ1�7�1�7�1�7b>          :  cb
	 * @<b>创建时间</b>      :  2013-6-9上午9:22:58      
	*/
	private float getDistance(float sX,float sY,float eX,float eY){
		float dx=eX-sX;
		float dy=eY-sY;
		float distance=(float) Math.sqrt((dx*dx)+(dy*dy));
		return distance;
	}
	
	private float getArea(MotionEvent event){
		float sX=event.getX(0);
		float sY=event.getY(0);
		float eX=event.getX(1);
		float eY=event.getY(1);
		float a=getDistance(sX, sY, eX, eY);
		eX = event.getX(2);
		eY = event.getY(2);
		float b=getDistance(sX, sY, eX, eY);
		sX = event.getX(1);
		sY = event.getY(1);
		float c=getDistance(sX, sY, eX, eY);
		float area=getArea(a, b, c);
		return area;
	}
	
	private float getArea(float a,float b,float c){
		float p=(a+b+c)/2;
		float s=(float) Math.sqrt(p*(p-a)*(p-b)*(p-c));
		return s;
	}
	
	private void debug(String text){
		LogUtils.d("debug", text);
	}
	
	protected  boolean onDown(float x,float y) {
		return false;
	}
	protected  boolean onMove(float startX,float nowX,float startY,float nowY) {
		return false;
	}
	protected  boolean onUp(float x,float y) {
		return false;
	}
	protected  boolean onZoom(float scale,float source) {
		return false;
	}
	protected  boolean onTripleZoom(float scale) {
		return false;
	}
	protected  boolean onDoubleTouchTown() {
		return false;
	}
	protected  boolean onTripleTouchTown() {
		return false;
	}
	protected  boolean onSlipLeft(float deltaX) {
		return false;
	}
	protected  boolean onSlipRight(float deltaX) {
		return false;
	}
	protected  boolean onSlipUp(float deltaY) {
		return false;
	}
	protected  boolean onSlipDown(float deltaY) {
		return false;
	}
	protected  boolean onClick() {
		return false;
	}
	protected  boolean onLongClick(float x,float y) {
		return false;
	}
	protected  void onPress(float x,float y){
	}
	protected  void onReStore(float x,float y){}
	protected  void onTouch() {
	}
	public float getFinalTripleZoom(){
		return mNowArea/mOriArea;
	}
	
	/**
	 * ClassName:MyHandler
	 * Function: 用于计时确认是否长按
	 * Reason:	 判断长按与否使用的变量mbCanBeClick、mbIsSingleDown是通用的，这就存在这种情况：第一次按下的时间和第二次按下的时间间隔很短（小于长按判定的
	 * 时间），第一次操作可能是划屏，然后第二次却不动，这样mbCanBeClick、mbIsSingleDown的值都是true，然后定时时间到了之后，使用的是第二次触屏的变量去判断
	 * 第一次是否长按，这样的结果是不准确的，因此要给每一个handler加一个id，以此区分是哪一次的触屏事件
	 * 
	 * 
	 * @author   cb
	 * @version  MotionEventManager
	 * @since    Ver 1.2
	 * @Date	 2013	2013-9-27		下午5:06:07
	 *
	 * @see 	 
	 */
	private class MyHandler extends Handler{
		private int mId;
		public void setId(int id){
			mId=id;
		}
		public boolean isIdChanged(int newId){
			return mId!=newId;
		}
	}
}
